package hikari.gui;

import com.gooddies.ballontips.ToolTipHandler;
import com.gooddies.swing.hList;
import com.gooddies.texteditors.DefaultTextField;
import com.gooddies.wiring.Wiring;
import hikari.preferences.GameProperties;
import hikari.utils.Utils;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import net.miginfocom.swing.MigLayout;

/**
 * @author Dmitry
 */
public class SceneChooserDialog extends JDialog {

    enum TYPE {

        SAVE, OPEN
    };
    private hList<String> scenesList;
    private JButton okButton;
    private String selectedScene = null;
    private TYPE dialogType;
    private DefaultTextField newSceneNameField;

    public SceneChooserDialog(Frame owner) {
        super(owner, true);
    }

    private void init() {
        setLayout(new MigLayout());
        selectedScene = null;
        checkSceneFolder();
        scenesList = new hList<>();
        scenesList.setPreferredSize(new Dimension(300, 400));
        scenesList.getJList().addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    scenesListDblClick();
                }
            }
        });

        add(scenesList, "spanx 10, wrap");
        okButton = new JButton(dialogType == TYPE.SAVE ? "Save" : "Open");
        okButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (check()) {
                    if (dialogType == TYPE.SAVE) {
                        selectedScene = newSceneNameField.getText();
                    } else {
                        selectedScene = scenesList.getSelectedItem();
                    }

                    close();
                }
            }
        });

        if (dialogType == TYPE.SAVE) {
            setTitle("Save scene");
            newSceneNameField = new DefaultTextField(100);
            newSceneNameField.setPreferredSize(new Dimension(300, 20));
            add(newSceneNameField, "spanx 10, wrap");
        } else {
            setTitle("Open scene");
        }

        add(okButton);
        JButton cancelButton = new JButton("Cancel");
        cancelButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                close();
            }
        });

        add(cancelButton);
        readScenesList();
        pack();
        setLocationRelativeTo(null);
    }

    private void scenesListDblClick() {
        if (scenesList.getSelectedIndex() == -1) {
            return;
        }

        selectedScene = scenesList.getSelectedItem();
        if (dialogType == TYPE.SAVE) {
            newSceneNameField.setText(selectedScene);
        }

        if (!check()) {
            return;
        }

        close();
    }

    private boolean isSceneAlreadyExist(String name) {
        int itemsCount = scenesList.getItemCount();
        for (int i = 0; i < itemsCount; i++) {
            if (name.equals(scenesList.getItem(i))) {
                return true;
            }
        }

        return false;
    }

    private boolean check() {
        if (dialogType == TYPE.SAVE) {
            String tSelectedScene = newSceneNameField.getText().trim();
            if (tSelectedScene.isEmpty()) {
                ToolTipHandler.error(newSceneNameField, "Scene name should not be empty");
                return false;
            }

            if (isSceneAlreadyExist(tSelectedScene)) {
                int result = JOptionPane.showConfirmDialog(this, "Scene with such name already exist. Are you want to replace it?", "Confirm", JOptionPane.YES_NO_OPTION);
                if (result == JOptionPane.NO_OPTION) {
                    return false;
                }
            }
        } else {
            if (scenesList.getItemCount() == 0) {
                ToolTipHandler.error(okButton, "No scene to open");
                return false;
            }

            if (scenesList.getSelectedIndex() == -1) {
                ToolTipHandler.error(scenesList, "Please select scene");
                return false;
            }
        }

        return true;
    }

    public static File formatSceneFile(String sceneName) {
        File file = new File(Wiring.getComponent(GameProperties.class).getSceneFolder());
        if (!sceneName.toLowerCase().endsWith(".scn")) {
            sceneName = sceneName + ".scn";
        }

        file = new File(file, sceneName);
        return file;
    }

    private void close() {
        setVisible(false);
    }

    private void checkSceneFolder() {
        File file = new File(Wiring.getComponent(GameProperties.class).getSceneFolder());
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    private void readScenesList() {
        File file = new File(Wiring.getComponent(GameProperties.class).getSceneFolder());
        for (File scene : file.listFiles()) {
            if (scene.isFile()) {
                String ext = Wiring.getComponent(Utils.class).getFileExtension(scene.getAbsolutePath());
                if ("scn".equals(ext)) {
                    String name = Wiring.getComponent(Utils.class).getFileNameWithoutExtension(scene.getAbsolutePath());
                    scenesList.addItem(name);
                }
            }
        }
    }

    /**
     * Returns name of the scene to save
     *
     * @return if <b>null</b>, it means that cancel was pressed
     */
    public String saveScene() {
        dialogType = TYPE.SAVE;
        init();

        setVisible(true);
        return selectedScene;
    }

    /**
     * Returns name of the scene to open
     *
     * @return if <b>null</b>, it means that cancel was pressed
     */
    public String openScene() {
        dialogType = TYPE.OPEN;
        init();

        setVisible(true);
        return selectedScene;
    }
}
